#include "time_slot_manager.h"
#include "uc_wiota_api.h"
#include "userid_manager.h"
#include <rtdevice.h>
#include <rtthread.h>
#define DBG_ENABLE
#define DBG_SECTION_NAME "ts_mn"
#include "uc_log.h"

#define SLOT_INFO_SEND_PERIOD 1000 // 1s
#define AUTH_FRAME_NUM 3           // 一次鉴权需要3帧
#define AUTH_FRAME_PERIOD 10       // 鉴权帧间隔10帧
#define TS_DATA_CACHE_LEN (50 * 1024)

typedef struct data_transport
{
    unsigned char ul_once_need_frame;
    unsigned char dl_once_need_frame;
    unsigned char transport_once_need_frame;
} data_transport_t;

static data_transport_t g_data_transport_info = {0}; // 一次数据传输要发送多少帧，用于网关分配发送时隙的计算
static unsigned int g_idle_ts_max;                   // 空闲时隙最大值，随着鉴权成功终端个数增多，逐渐减小
static time_slot_bc_t g_time_slot_info = {0};        // 网关广播分时发送信息结构
static int g_time_slot_num = 0;                      // 总的时隙个数
static unsigned char g_is_ts_mode = 0;               // 是否为分时模式

// 定帧接收信息
static sf_info_t *g_sf_info = RT_NULL;
static unsigned int g_cur_cache_size = 0;
static void (*g_bc_ts_info_cb)(time_slot_bc_t *ts_info) = RT_NULL;

/**
 * @brief 获取定帧收发结构体指针
 *
 * @return sf_info_t* 定帧收发结构体指针
 */
sf_info_t *manager_get_sf_info_addr(void)
{
    return g_sf_info;
}

/**
 * @brief 获取是否为分时模式
 *
 * @return unsigned char 是否为分时模式
 */
unsigned char manager_get_is_ts_mode(void)
{
    return g_is_ts_mode;
}

/**
 * @brief 获取总时隙数
 *
 * @return int 总时隙数
 */
int manager_get_time_slot_num(void)
{
    return g_time_slot_num;
}

/**
 * @brief  计算时隙信息
 *
 * @param  slot_cfg        时隙配置
 * @param  ts_info         网关广播分时发送信息结构计算返回
 * @param  data_trans_info 一次数据传输要发送多少帧，用于网关分配发送时隙的计算
 * @return int             数据计算结果 0:成功; <0:失败
 */
int manager_time_slot_info_update(void *slot_cfg, void *ts_info, void *data_trans_info)
{
    const unsigned short MCS_TABLE_WITHOUT_CRC[4][8] = {
        {7, 9, 52, 66, 80, 0, 0, 0},
        {7, 15, 22, 52, 108, 157, 192, 0},
        {7, 15, 31, 42, 73, 136, 255, 297},
        {7, 15, 31, 63, 108, 220, 451, 619},
    };
    slot_rs_cfg_t *slot_rs_cfg = (slot_rs_cfg_t *)slot_cfg;
    time_slot_bc_t *app_ts_info = (time_slot_bc_t *)ts_info;
    data_transport_t *data_transport_info = (data_transport_t *)data_trans_info;
    sub_system_config_t config;
    unsigned int frame_len = manager_get_frame_len();
    if (frame_len == 0)
    {
        return -RT_ERROR;
    }
    uc_wiota_get_system_config(&config);

    unsigned char symbol_len = config.symbol_length;
    unsigned short ul_max_len = slot_rs_cfg->ul_max_len;
    unsigned short dl_max_len = slot_rs_cfg->dl_max_len;
    unsigned char ul_resend_times = slot_rs_cfg->ul_resend_times;
    unsigned char dl_resend_times = slot_rs_cfg->dl_resend_times;
    unsigned char ul_mcs = slot_rs_cfg->ul_mcs;
    unsigned char dl_mcs = slot_rs_cfg->dl_mcs;
    unsigned char ul_subframe_num = (1 << config.group_number) * 8;
    unsigned int data_transport_period = slot_rs_cfg->data_transport_period;
    unsigned int pof = data_transport_period * 1000 / frame_len;

    unsigned short ul_active_len = (MCS_TABLE_WITHOUT_CRC[symbol_len][ul_mcs] - 1);
    unsigned short dl_active_len = (MCS_TABLE_WITHOUT_CRC[symbol_len][dl_mcs] - 1);
    unsigned char data_transport_once_need_frame = 0;
    unsigned short device_access_max = 0;
    unsigned int real_data_transport_period = 0;
    unsigned char auth_period = 0;
    unsigned int real_pof = 0;
    unsigned int integer_period = 0;
    unsigned int remainder_frame_num = 0;
    unsigned int remainder_frame_for_device_num = 0;
    unsigned char ul_once_need_frame = ul_max_len / ul_active_len;
    unsigned char dl_once_need_frame = dl_max_len / dl_active_len;

    if (ul_max_len % ul_active_len != 0)
    {
        ul_once_need_frame += 1;
    }
    ul_once_need_frame *= (ul_resend_times + 1);

    if (dl_max_len % dl_active_len != 0)
    {
        dl_once_need_frame += 1;
    }
    dl_once_need_frame *= (dl_resend_times + 1);
    if (dl_once_need_frame != 0)
    {
        dl_once_need_frame += 1;
    }
    data_transport_once_need_frame = ul_once_need_frame + dl_once_need_frame;

    // 如果pof小于一个设备的一次数据传输时隙数+鉴权帧数，则设置错误
    if (pof < (data_transport_once_need_frame + AUTH_FRAME_NUM))
    {
        real_pof = data_transport_once_need_frame + AUTH_FRAME_NUM;
        slot_rs_cfg->device_access_max = 0;
        slot_rs_cfg->real_data_transport_period = (real_pof * frame_len / 1000) + 1;
        return -RT_ERROR;
    }

    // 如果数据传输时隙数小于6，则根据pof设置鉴权周期，6是根据最大鉴权周期15计算得出，最大鉴权周期15为自定义值，无计算方法
    if (data_transport_once_need_frame <= 6)
    {
        unsigned int temp_pof = pof;
        if (temp_pof > 15)
            temp_pof = 15;
        // 计算鉴权周期，周期内鉴权帧和业务帧将填满周期，不会留空闲帧
        auth_period = ((temp_pof - AUTH_FRAME_NUM) / data_transport_once_need_frame) * data_transport_once_need_frame + AUTH_FRAME_NUM;
    }
    else
    {
        auth_period = data_transport_once_need_frame + AUTH_FRAME_NUM;
    }

    // 计算完整周期个数，例如周期为15，pof为20，则只有一个完整周期
    integer_period = pof / auth_period;
    // 计算剩余帧数，例如周期为15，pof为20，则有5个剩余帧
    remainder_frame_num = pof - (integer_period * auth_period);
    // 剩余帧数所能容纳的设备个数
    remainder_frame_for_device_num = 0;
    // 计算剩余帧数所能容纳的设备个数，如果剩余时隙大于等于一个设备所需帧数加鉴权帧数，则剩余帧数还能容纳设备
    if (remainder_frame_num >= (data_transport_once_need_frame + AUTH_FRAME_NUM))
    {
        // 剩余帧数减去鉴权帧数，除以数据传输时隙数，得到剩余帧数所能容纳的设备个数
        remainder_frame_for_device_num = (remainder_frame_num - AUTH_FRAME_NUM) / data_transport_once_need_frame;
        // 计算实际的pof，完整周期个数乘以周期帧数加上鉴权帧数，再加上剩余帧数所能容纳的设备个数乘以数据传输时隙数
        real_pof = (integer_period * auth_period) + AUTH_FRAME_NUM + (remainder_frame_for_device_num * data_transport_once_need_frame);
    }
    else
    {
        // 剩余帧数不足以容纳一个设备，则实际的pof为完整周期个数乘以周期帧数
        real_pof = integer_period * auth_period;
    }

    // 计算device_access_max，一个鉴权周期的帧数减去鉴权帧数，再除以一次数据传输所需帧数，等于一个周期一个时隙能容纳的设备个数
    // 设备个数乘以完整周期个数，加上剩余帧数所能容纳的设备个数，再乘以一个上行group所能容纳的设备数
    // 等于最大能容纳设备个数
    device_access_max = (((auth_period - AUTH_FRAME_NUM) / data_transport_once_need_frame) * integer_period + remainder_frame_for_device_num) * ul_subframe_num;
    // 计算实际的数据发送周期，实际的pof乘以帧时间，加1是向上取整
    real_data_transport_period = (real_pof * frame_len / 1000) + 1;

    if (ts_info != RT_NULL)
    {
        app_ts_info->pof = real_pof;
        app_ts_info->auth_period = auth_period;
        app_ts_info->resend_times = ul_resend_times;
        app_ts_info->mcs = ul_mcs;
    }

    if (data_transport_info != RT_NULL)
    {
        data_transport_info->ul_once_need_frame = ul_once_need_frame;
        data_transport_info->dl_once_need_frame = dl_once_need_frame;
        data_transport_info->transport_once_need_frame = data_transport_once_need_frame;
    }

    slot_rs_cfg->device_access_max = device_access_max;
    slot_rs_cfg->real_data_transport_period = real_data_transport_period;

    TRACE_I("time_slot_info: pof %d, auth_period %d, ul_once_need_frame: %d, dl_once_need_frame %d",
            real_pof, auth_period, ul_once_need_frame, dl_once_need_frame);

    {
        unsigned char index = 0;
        unsigned char cut_index = 0;
        char all_picture[64] = {0};
        rt_memset(all_picture, 0, sizeof(all_picture));
        rt_snprintf(&all_picture[index], (AUTH_FRAME_NUM + 1), "###");
        index = AUTH_FRAME_NUM;
        rt_snprintf(&all_picture[index], (3 + 1), " | ");
        cut_index = 3;
        index += cut_index;
        do
        {
            if (ul_once_need_frame > 0)
            {
                rt_snprintf(&all_picture[index], (ul_once_need_frame + 1), "+++++++++++++++");
                index += ul_once_need_frame;
                rt_snprintf(&all_picture[index], (1 + 1), " ");
                cut_index += 1;
                index += 1;
            }
            if (dl_once_need_frame > 0)
            {
                rt_snprintf(&all_picture[index], (dl_once_need_frame + 1), "---------------");
                index += dl_once_need_frame;
                rt_snprintf(&all_picture[index], (1 + 1), " ");
                cut_index += 1;
                index += 1;
            }
            if ((index - cut_index) >= auth_period)
            {
                break;
            }
            rt_snprintf(&all_picture[index], (2 + 1), "| ");
            cut_index += 2;
            index += 2;
        } while (1);

        TRACE_I("[ %s] x %d + %d", all_picture, integer_period, remainder_frame_for_device_num);
    }

    return RT_EOK;
}

/**
 * @brief 初始化时隙信息，必须在网关ID管理初始化之后调用
 *
 * @param slot_rs_cfg            分时收发配置
 * @param bc_time_slot_info_cb   广播时隙信息回调函数，为空时表示不发送广播时隙信息
 * @param uc_fn_refresh_callback 帧号更新回调函数
 * @return int                   0成功; 非0失败
 */
int manager_time_slot_info_init(slot_rs_cfg_t *slot_rs_cfg, void(*bc_time_slot_info_cb), void(*uc_fn_refresh_callback))
{
    if (slot_rs_cfg->data_transport_period == 0)
    {
        // TRACE_E("ul_send_period is 0, not require to init time_slot_info");
        return 0;
    }

    if (RT_EOK != manager_time_slot_info_update(slot_rs_cfg, &g_time_slot_info, &g_data_transport_info))
    {
        TRACE_E("manager_time_slot_info_update failed");
        return 1;
    }

    TRACE_I("slot_rs_cfg: data_transport_period %u, bc_period %d, alive_timeout %d",
            slot_rs_cfg->data_transport_period, slot_rs_cfg->bc_frame_send_period, slot_rs_cfg->alive_timeout);
    TRACE_I("ul_len %d, dl_len %d, ul_resend_times %d, dl_resend_times %d, ul_mcs %d, dl_mcs %d",
            slot_rs_cfg->ul_max_len, slot_rs_cfg->dl_max_len,
            slot_rs_cfg->ul_resend_times, slot_rs_cfg->dl_resend_times,
            slot_rs_cfg->ul_mcs, slot_rs_cfg->dl_mcs);
    TRACE_I("device_access_max %d, real_data_transport_period %u", slot_rs_cfg->device_access_max, slot_rs_cfg->real_data_transport_period);

    manager_ul_time_slot_fn_init();

    RT_ASSERT(manager_get_ul_subframe_num() != 0);

    g_bc_ts_info_cb = bc_time_slot_info_cb;
    // 分时收发的上下行采用定帧收发的策略
    manager_recv_send_by_fn_init(slot_rs_cfg, uc_fn_refresh_callback);

    g_is_ts_mode = 1;

    return 0;
}

/**
 * @brief 反初始化时隙信息
 *
 */
void manager_time_slot_info_deinit(void)
{
    g_is_ts_mode = 0;
    g_cur_cache_size = 0;
    g_bc_ts_info_cb = RT_NULL;
    uc_wiota_register_fn_refresh_callback(RT_NULL);
}

/**
 * @brief 更新时隙分配值，随着鉴权成功终端个数增多，鉴权时隙逐渐减少
 *
 */
void manager_update_ul_time_slot_fn(void)
{
    // 不是分时收发模式，不添加定帧信息
    if (0 == g_is_ts_mode)
    {
        return;
    }

    // 鉴权时隙逐渐减小，idle_ts_max是未分配时隙的最大值，每次更新减小这个值
    if ((g_idle_ts_max - AUTH_FRAME_NUM) % g_time_slot_info.auth_period == 0)
    {
        g_idle_ts_max -= AUTH_FRAME_NUM;
    }

    if (g_idle_ts_max > g_data_transport_info.transport_once_need_frame)
        g_idle_ts_max -= g_data_transport_info.transport_once_need_frame;

    // 鉴权时隙减小后，g_idle_ts_max可能小于AUTH_FRAME_NUM，需要重新设置g_idle_ts_max
    if (g_idle_ts_max < AUTH_FRAME_NUM)
    {
        TRACE_W("idle_ts_max %d is less than auth_frame_num %d", g_idle_ts_max, AUTH_FRAME_NUM);
        manager_ul_time_slot_fn_init();
    }
}

/**
 * @brief  获取数组下标，实际上是时隙分配值去掉鉴权帧数所在的实际位置
 *
 * @param  time_slot_fn 当前时隙值
 * @return int 数组下标 <0 表示无效
 */
int manager_get_ul_time_slot_fn_pos(int time_slot_fn)
{
    if (time_slot_fn < 0)
    {
        return -1;
    }
    unsigned int integer_time_slot_fn = (time_slot_fn / g_time_slot_info.auth_period) * (g_time_slot_info.auth_period - AUTH_FRAME_NUM);
    int remainder_time_slot_fn = (time_slot_fn - ((time_slot_fn / g_time_slot_info.auth_period) * g_time_slot_info.auth_period) - AUTH_FRAME_NUM);

    if (remainder_time_slot_fn < 0 || (integer_time_slot_fn + remainder_time_slot_fn) % g_data_transport_info.transport_once_need_frame != 0)
    {
        return -2;
    }

    return ((integer_time_slot_fn + remainder_time_slot_fn) / g_data_transport_info.transport_once_need_frame);
}

/**
 * @brief  获取时隙分配值，实际为空闲时隙的最大值，从大到小分配
 *
 * @return unsigned short 实际空闲的时隙值
 */
unsigned short manager_get_ul_time_slot_fn(void)
{
    return g_idle_ts_max;
}

/**
 * @brief  时隙分配值初始化
 *
 */
void manager_ul_time_slot_fn_init(void)
{
    g_idle_ts_max = g_time_slot_info.pof - g_data_transport_info.transport_once_need_frame;
}

/**
 * @brief  定帧接收，根据时隙分配值，将收到的帧号和用户ID存入数组
 *
 * @param wiota_id      用户ID
 * @param cur_time_slot 当前时隙
 *
 * @return int          0表示成功，其他则表示失败
 *
 */
int manager_add_recv_send_by_fn_info(unsigned int wiota_id, unsigned int cur_time_slot)
{
    // 不是分时收发模式，不添加定帧信息
    if (0 == g_is_ts_mode)
    {
        return 0;
    }

    RT_ASSERT(g_sf_info);

    if (wiota_id == 0)
    {
        return -1;
    }

    int index = manager_get_ul_time_slot_fn_pos(cur_time_slot);
    RT_ASSERT(index >= 0);
    if (index >= g_time_slot_num)
    {
        TRACE_E("sf_recv_list invalid index %d, wiota_id 0x%x, ts %d", index, wiota_id, cur_time_slot);
        return -2;
    }
    unsigned int id_index = g_sf_info[index].dev_num;
    if (id_index >= manager_get_ul_subframe_num())
    {
        TRACE_E("sf_recv_list is full, wiota_id 0x%x, ts %d, index %d, dev_num %d", wiota_id, cur_time_slot, index, id_index);
        return -3;
    }

    g_sf_info[index].sf_send[id_index].wiota_id = wiota_id;
    g_sf_info[index].dev_num++;

    TRACE_I("sf_recv_list add 0x%x, index %d, ts %d, dev_num %d", wiota_id, index, cur_time_slot, g_sf_info[index].dev_num);

    return 0;
}

/**
 * @brief 分时模式缓存数据长度增加
 *
 * @param revert_len
 */
int manager_cache_size_add(unsigned int add_len)
{
    if (g_cur_cache_size < TS_DATA_CACHE_LEN)
    {
        rt_enter_critical();
        g_cur_cache_size += add_len;
        rt_exit_critical();
    }
    else
    {
        TRACE_E("cache_size is full, cur_cache_size %d", g_cur_cache_size);
        return 1;
    }
    return 0;
}

/**
 * @brief 分时模式缓存数据长度回退
 *
 * @param revert_len
 */
void manager_cache_size_revert(unsigned int revert_len)
{
    rt_enter_critical();
    if (g_cur_cache_size > 0 && g_cur_cache_size >= revert_len)
    {
        g_cur_cache_size -= revert_len;
    }
    rt_exit_critical();
}

/**
 * @brief 如果时分时收发模式，则缓存下行定帧数据
 *
 * @param data          编码后的数据
 * @param data_len      数据长度
 * @param wiota_id      用户ID
 * @param cur_time_slot 当前时隙
 *
 * @return int          0表示数据已缓存，其他则表示不需要缓存或缓存失败
 */
int manager_cache_recv_send_data_by_fn(unsigned char *data, unsigned int data_len, unsigned int wiota_id, unsigned int cur_time_slot)
{
    // 不是分时收发模式，不缓存数据
    if (0 == g_is_ts_mode)
    {
        return 1;
    }

    int index = manager_get_ul_time_slot_fn_pos(cur_time_slot);
    int dev_num = g_sf_info[index].dev_num;

    for (int i = 0; i < dev_num; i++)
    {
        if (g_sf_info[index].sf_send[i].wiota_id == wiota_id)
        {
            sf_data_node_t *data_node = (sf_data_node_t *)rt_malloc(sizeof(sf_data_node_t));
            RT_ASSERT(data_node);

            data_node->data = data;
            data_node->data_len = data_len;

            rt_list_insert_after(&g_sf_info[index].sf_send[i].data_list, &data_node->node);
            // TRACE_D("cache data to sf_send_list, index %d, ts %d, wiota_id 0x%x, data_len %d", index, cur_time_slot, wiota_id, data_len);
            return 0;
        }
    }

    return 3;
}

/**
 * @brief 根据帧号获取当前时隙的定帧收发信息
 *
 * @param frame_num  当前帧号
 * @return sf_info_t 不为RT_NULL表示时隙有效，为NULL表示无效
 */
sf_info_t *manager_get_sf_info_by_fn(unsigned int frame_num)
{
    unsigned int cur_time_slot = frame_num % g_time_slot_info.pof;
    int index = manager_get_ul_time_slot_fn_pos(cur_time_slot);

    g_time_slot_info.frame_num = frame_num;

    if (g_bc_ts_info_cb && (frame_num % g_time_slot_info.auth_period == 0))
    {
        g_bc_ts_info_cb(&g_time_slot_info);
    }

    if (index >= 0 && g_sf_info[index].dev_num > 0)
    {
        g_sf_info[index].ts_fn = cur_time_slot;
        g_sf_info[index].frame_num = frame_num;
        g_sf_info[index].ul_recv_fns = g_data_transport_info.ul_once_need_frame;
        g_sf_info[index].dl_send_fns = g_data_transport_info.dl_once_need_frame;
        g_sf_info[index].ts_index = index;

        return &g_sf_info[index];
    }

    return RT_NULL;
}

/**
 * @brief 定帧收发初始化
 *
 *@param slot_rs_cfg            时隙收发配置
 *@param uc_fn_refresh_callback 帧号刷新回调
 */
void manager_recv_send_by_fn_init(slot_rs_cfg_t *slot_rs_cfg, void(*uc_fn_refresh_callback))
{
    unsigned char ul_subf_num = manager_get_ul_subframe_num();
    g_time_slot_num = slot_rs_cfg->device_access_max / ul_subf_num;

    // TRACE_D("device_access_max %d, ul_subframe_num %d, time_slot_num %d",
    //         device_access_max, ul_subf_num, g_time_slot_num);

    g_sf_info = (sf_info_t *)rt_malloc(sizeof(sf_info_t) * g_time_slot_num);
    RT_ASSERT(g_sf_info);
    rt_memset(g_sf_info, 0, sizeof(sf_info_t) * g_time_slot_num);

    for (int i = 0; i < g_time_slot_num; i++)
    {
        g_sf_info[i].sf_send = (sf_send_info_t *)rt_malloc(sizeof(sf_send_info_t) * ul_subf_num);
        RT_ASSERT(g_sf_info[i].sf_send);
        rt_memset(g_sf_info[i].sf_send, 0, sizeof(sf_send_info_t) * ul_subf_num);
        for (int j = 0; j < ul_subf_num; j++)
        {
            rt_list_init(&g_sf_info[i].sf_send[j].data_list);
        }
    }

    g_cur_cache_size = 0;

    // 注册帧号刷新回调
    uc_wiota_register_fn_refresh_callback(uc_fn_refresh_callback);
    // 该模式下单播的网关重发次数为0，且协议栈重发次数根据分时收发配置来决定
    uc_wiota_set_sm_resend_times(slot_rs_cfg->dl_resend_times);

    TRACE_D("manager_recv_send_by_fn_init success\n");
}
